package com.hzw.saas.service.group.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.group.IGroupLogService;
import com.hzw.saas.api.group.IGroupMemberService;
import com.hzw.saas.api.group.IGroupResourceService;
import com.hzw.saas.api.group.IGroupService;
import com.hzw.saas.api.group.bo.GroupBo;
import com.hzw.saas.api.group.bo.GroupResourceBO;
import com.hzw.saas.api.group.query.GroupLogQuery;
import com.hzw.saas.api.storage.IResourceFileService;
import com.hzw.saas.api.storage.bo.ResourceFileBO;
import com.hzw.saas.api.storage.enums.FileIntegrityEnum;
import com.hzw.saas.api.storage.enums.ResourceStatusEnum;
import com.hzw.saas.api.user.IUserAccountService;
import com.hzw.saas.api.user.IUserProfileService;
import com.hzw.saas.api.user.bo.UserAccountBO;
import com.hzw.saas.api.user.bo.UserProfileBO;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.util.Json;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.service.group.mapper.GroupResourceMapper;
import com.hzw.saas.service.group.model.GroupResource;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zzl
 * @since 12/24/2020
 */
@Service
@RequiredArgsConstructor
public class GroupResourceServiceImpl extends ServiceImpl<GroupResourceMapper, GroupResource> implements IGroupResourceService, IService<GroupResource> {

    private final IUserAccountService userAccountService;
    private final IUserProfileService userProfileService;
    private final IResourceFileService fileService;
    private final IGroupService groupService;
    private final IGroupMemberService groupMemberService;
    private final IGroupLogService groupLogService;


    @Override
    public GroupResourceBO getGroupFile(String fileId) {
        // 获取资源和共享信息
        ResourceFileBO fileInfo = fileService.getFile(fileId, AssertEnum.FOUND);
        return this.assembleGroups(fileInfo);
    }

    @Override
    public GroupResourceBO assembleGroups(ResourceFileBO fileInfo) {
        GroupResourceBO result = MapperUtil.nf().map(fileInfo, GroupResourceBO.class);
        if (StringUtils.isBlank(fileInfo.getPid()))
            return result;
        List<GroupResource> groupResources = this.lambdaQuery().eq(GroupResource::getFileId, fileInfo.getPid()).list();
        List<String> groupIds = groupResources.stream().map(GroupResource::getGroupId).collect(Collectors.toList());
        // 组装groupIds
        result.addGroupIds(groupIds);
        return result;
    }

    @Override
    public List<GroupResourceBO> assembleGroups(List<ResourceFileBO> fileInfoList) {
        List<GroupResourceBO> result = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(fileInfoList)) {
            for (ResourceFileBO fileBO : fileInfoList) {
                result.add(this.assembleGroups(fileBO));
            }
        }
        return result;
    }

    @Override
    public int countGroupFile(String groupId, String ownerId) {
        if (StringUtils.isBlank(groupId) && StringUtils.isBlank(ownerId)) return 0;
        return this.baseMapper.countGroupFile(groupId, ownerId,
            ResourceStatusEnum.NORMAL.getCode(), FileIntegrityEnum.NORMAL.getCode());
    }

    @Override
    public IPage<ResourceFileBO> listGroupFileInfo(PageParam page, String groupId, String ownerId) {
        // 获取共享资源信息
        IPage<GroupResource> resources = this.baseMapper.listGroupFileInfo(
            page.convert(), groupId, ownerId, ResourceStatusEnum.NORMAL.getCode(), FileIntegrityEnum.NORMAL.getCode());
        List<String> fileIdList = resources.getRecords().stream().map(GroupResource::getFileId).collect(Collectors.toList());
        // 获取资源信息
        List<ResourceFileBO> fileInfoList = this.fileService.listFiles(fileIdList);
        // 返回结果
        IPage<ResourceFileBO> pageResult = new Page<>(resources.getCurrent(), resources.getSize(),
            resources.getTotal());
        pageResult.setRecords(fileInfoList);
        return pageResult;
    }

    @Override
    public boolean existGroupFile(String groupId, String fileId) {
        int count =
            this.lambdaQuery().eq(GroupResource::getGroupId, groupId).eq(GroupResource::getFileId, fileId).count();
        return count > 0;
    }

    @Override
    public void addGroupFile(String groupId, String userId, String fileId) {
        GroupBo groupBo = groupService.getGroupById(groupId);
        // 检查群组是否存在
        AssertUtil.assertThrow("群组不存在：" + groupId, Objects.isNull(groupBo));
        AssertUtil.assertThrow("不能分享文件到默认群组", StringUtil.isBlank(groupBo.getOwnerId()));
        // 检查资源是否存在
        ResourceFileBO fileInfo = fileService.getFile(fileId, AssertEnum.FOUND);
        // 检查是否存在
        if (this.existGroupFile(groupId, fileId))
            return;
        // 持久化数据
        GroupResource groupResource = new GroupResource()
            .setGroupId(groupId)
            .setFileId(fileId)
            .setShareDate(new Date());
        this.save(groupResource);

        // 插入群组动态
        GroupLogQuery groupLog = new GroupLogQuery();
        groupLog.setGroupId(groupId);
        groupLog.setLogType(1);
        // 先用map存放群组动态数据
        Map<String, String> data = new HashMap<>();
        data.put("username", this.getRealName(userId));
        data.put("msg", String.format("共享了%s", fileInfo.getName()));
        groupLog.setLogMsg(Json.toJsonString(data));
        groupLogService.addGroupLog(groupLog);
    }

    @Override
    public void deleteGroupFile(String groupId, String userId, String fileId) {
        // 校验参数
        AssertUtil.assertThrow("群组ID和资源ID不可同时为空", StrUtil.isAllBlank(groupId, fileId));

        List<GroupResource> groupResources = this.lambdaQuery()
            .eq(StringUtils.isNotBlank(groupId), GroupResource::getGroupId, groupId)
            .eq(StringUtils.isNotBlank(fileId), GroupResource::getFileId, fileId).list();
        if (CollectionUtils.isEmpty(groupResources))
            return;
        // 持久化数据
        List<String> idList = groupResources.stream().map(GroupResource::getRefId).collect(Collectors.toList());
        this.removeByIds(idList);

        for (GroupResource groupResource : groupResources) {
            // 插入群组动态
            ResourceFileBO resourceFileBo = this.fileService.getFile(groupResource.getFileId(), AssertEnum.FOUND);
            GroupLogQuery groupLog = new GroupLogQuery();
            groupLog.setGroupId(groupResource.getGroupId());
            groupLog.setLogType(1);
            // 先用map存放群组动态数据
            Map<String, String> data = new HashMap<>();
            data.put("username", this.getRealName(userId));
            data.put("msg", String.format("取消共享%s", resourceFileBo.getName()));
            groupLog.setLogMsg(Json.toJsonString(data));
            groupLogService.addGroupLog(groupLog);
        }
    }

    @Override
    public boolean checkAuthRead(String userId, String fileId) {
        // 为本人的资源
        boolean checkUserOwner = fileService.checkAuthOwn(userId, fileId);
        if (checkUserOwner)
            return true;
        // 为本人所在群组的分享资源
        List<GroupResource> groupResources = super.lambdaQuery().eq(GroupResource::getFileId, fileId).list();
        if (CollectionUtils.isEmpty(groupResources))
            return false;
        for (GroupResource groupResource : groupResources) {
            if (!groupService.doesExist(groupResource.getGroupId()))
                continue;
            if (groupMemberService.tryJoinGroup(userId, groupResource.getGroupId()))
                return true;
        }
        return false;
    }

    private String getRealName(String userId) {
        UserProfileBO userProfileBO = userProfileService.get(userId);
        if(userProfileBO == null || StrUtil.isBlank(userProfileBO.getRealName())) {
            UserAccountBO account = userAccountService.getAccount(userId);
            return account == null ? "null" : account.getUserName();
        }
        return userProfileBO.getRealName();
    }
}
